/*****************************************************************************
 * $LastChangedDate: 2011-04-23 21:07:07 -0400 (Sat, 23 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Matrix functions (OSG).
 *//*
 * LEGAL:   COPYRIGHT (C) 2007 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#define MATH_MATRIX_FUNCS_CC 1
#include "base/module.hh"
#include "base/stream.hh"
using namespace base;
#include "math/module.hh"
#include "math/matrix.hh"
#include "math/matrix_funcs.hh"
#include "math/quaternion.hh"

namespace math {

////////////////////////////////////////////////////////////////////////////////
/////////////////////////////  Matrix class  ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*****************************************************************************
 * ctor.
 * Quaternion only defines rotation (osg::Matrix(quat) produces zero position),
 * so position must be assigned afterwards.
 *****************************************************************************/
Matrix::Matrix( const Quaternion& quat, const Vector3& v )
:   osg::Matrix(quat)
{
    SetPosition( v );
}

////////////////////////////////////////////////////////////////////////////////
///////////////////////////////  functions  ////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*****************************************************************************
 * Scale a MatrixTransform node.
 * Can effectively scale an Object.
 *****************************************************************************/
void
MatrixScale( osg::MatrixTransform& transform /*IN/OUT*/, const Vector3& scale )
{
    osg::Matrix scaleMatrix;
    scaleMatrix.makeScale( scale );
    osg::Matrix m = transform.getMatrix();
    m = scaleMatrix * m;
    transform.setMatrix( m );
}

/*****************************************************************************
 * Translate a MatrixTransform node.
 *****************************************************************************/
void
MatrixTranslate( osg::MatrixTransform& transform /*IN/OUT*/, const Vector3& offset )
{
    osg::Matrix m = transform.getMatrix();
    MatrixTranslate( m, offset );  // osg::Matrix
    transform.setMatrix( m );
}

/*****************************************************************************
 * For osg::MatrixTransform node.
 * Rotate matrix around local axis.
 * Rotate a local coordinate system around its own axis.
 *****************************************************************************/
void
MatrixRotateLocal( osg::MatrixTransform& transform /*IN/OUT*/, const uint axis, const Radian rad )
{
    osg::Matrix m = transform.getMatrix();
    MatrixRotateLocal<>( m, axis, rad );
    transform.setMatrix( m );
}

/*****************************************************************************
 * For osg::MatrixTransform node.
 * Rotate a matrix around a fixed axis.
 * This function is suited to rotating the viewpoint/eye.
 *****************************************************************************/
void
MatrixRotateFixed( osg::MatrixTransform& transform /*IN/OUT*/, const uint axis, const Radian rad )
{
    osg::Matrix m = transform.getMatrix();
    MatrixRotateFixed<>( m, axis, rad );
    transform.setMatrix( m );
}

/*****************************************************************************
 * operator<<().
 *****************************************************************************/
std::ostream& operator<<( std::ostream& strm, const Matrix& m )
{
    std::ios::fmtflags savedFlags = strm.flags();
    strm.setf( std::ios::fixed, std::ios::floatfield );
    strm.precision( 6 );
    strm << "Xxyzw:  " << m[Xx] << "  " << m[Xy] << "  " << m[Xz] << std::endl
         << "Yxyzw:  " << m[Yx] << "  " << m[Yy] << "  " << m[Yz] << std::endl
         << "Zxyzw:  " << m[Zx] << "  " << m[Zy] << "  " << m[Zz] << std::endl
         << "Oxyzw:  " << m[Ox] << "  " << m[Oy] << "  " << m[Oz]; // << std::endl;
    strm.flags(savedFlags);
    return strm;
}

} // namespace math
